#ifndef __MALLA__
#define __MALLA__
#include <cassert>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include "../matriz/matriz.h"
#include "../celda/celda.h"
#include "../dupla/dupla.h"

#include <sstream>
#include <fstream>
using namespace std;

#define ENTRADA 2
#define SALIDA 3

/**
 * CLASE MALLA
 * clase que crea maneja una malla en forma valida con entrada y salida fija
 * los constructores entregan una malla valida y los setters
 * solo cambian si hacer ese cambio mantiene el invariante de malla.
 */
class Malla {
    public:

        Malla(unsigned int);
        Malla(unsigned int size, const Celda& conexion);
        Malla(unsigned int size,const Celda& entrada,const Celda& salida);
        Malla(const Malla&);


        bool operator==(const Malla&);
        bool operator!=(const Malla&);
        Malla& operator=(const Malla&);


        bool setCelda(unsigned int fila, unsigned int columna);
        bool resetCelda(unsigned int fila, unsigned int columna);

        Celda getCelda(unsigned int, unsigned int) const;
        float getResistencia() const;
        int size() const;
        void mostrar(ostream& ) const;
        bool existe(const unsigned int, const unsigned int) const;
        void show(double val) const;

    private:
        /**
         * en la matriz cada codigo significa lo siguiente:
         * 0 = no hay celda
         * 1 = celda comun
         * 2 = celda entrada
         * 3 = celda salida
         * 4 = celda entrada y salida
         */
        Matriz matriz;
        Celda entrada;
        Celda salida;

        /** funciones internas */
        bool sonValidas() const;
        void pintarConectados(Matriz *, unsigned int, unsigned int) const;
        bool validar() const;
        bool conexionValida(const unsigned int, const unsigned int) const;
        void recorrerLaberinto(double* ultima, int * arrId, int tamanio) const;
        int direccionInicial(Dupla<int,int>& dir, Dupla<unsigned int,unsigned int>& pos) const;
        int proximaCelda(Dupla<int,int>& dir, Dupla<unsigned int,unsigned int>& pos, int esquina) const;
        bool esCelda(unsigned int fila, unsigned int columna) const;
        bool esCelda(Dupla<unsigned int, unsigned int> coord) const;

};



Malla::Malla(unsigned int size){
    assert(size > 0);
    matriz = Matriz(size);
    if(size == 1){
        Celda celda = Celda(SUDESTE, NOROESTE, 0, 0);
        entrada = celda;
        salida = celda;
        matriz.setPos(0,0,4);
    } else {
        entrada = Celda(SUDESTE, 0, matriz.size() - 1, matriz.size() - 1);
        salida = Celda(0, NOROESTE, 0, 0);
        matriz.setPos(matriz.size() - 1, matriz.size() - 1, ENTRADA);
        matriz.setPos(0, 0, SALIDA);
        unsigned int y;
        unsigned int x;
        y = 0;
        for(x = 1; x < entrada.fila; x++){
            matriz.setPos(x, y, 1);
        }
        x = entrada.fila;
        for(y = salida.columna; y < entrada.columna; y++){
            matriz.setPos(x, y, 1);
        }
    }
}

Malla::Malla(unsigned int size, const Celda& conexion){
    assert(size > 0);
    assert(conexion.fila < size);
    assert(conexion.columna < size);
    assert(conexion.esEntrada());
    assert(conexion.esSalida());
    this->matriz = *(new Matriz(size));
    this->entrada = conexion;
    this->salida = conexion;
    this->matriz.setPos(conexion.fila, conexion.columna, 4);
}

Malla::Malla(unsigned int size,const Celda& entrada,const Celda& salida){
    assert(size > 0);
    assert(entrada.fila < size);
    assert(entrada.columna < size);
    assert(salida.fila < size);
    assert(salida.columna < size);
    assert(entrada.esEntrada());
    assert(salida.esSalida());
    assert(entrada.fila != salida.fila || entrada.columna != salida.fila);
    this->matriz = *(new Matriz(size));
    this->entrada = entrada;
    this->salida = salida;
    assert(sonValidas());
    this->matriz.setPos(entrada.fila, entrada.columna, 2);
    this->matriz.setPos(salida.fila, salida.columna, 3);
    int xinicio, yinicio, yfin, xfin;
    if(entrada.fila < salida.fila){
        xinicio = entrada.fila;
        xfin    = salida.fila;
        yinicio = entrada.columna;
        yfin    = salida.columna;
    } else {
        xinicio = salida.fila;
        xfin    = entrada.fila;
        yinicio = salida.columna;
        yfin    = entrada.columna;
    }
    for(int x = xinicio+1; x < xfin; x++){
        this->matriz.setPos(x, yinicio, 1);
    }
    if(yinicio < yfin){
        for(int y = yinicio; y < yfin; y++){
            this->matriz.setPos(xfin, y, 1);
        }
    }else if(yfin < yinicio){
        for(int y = yfin + 1; y <= yinicio;y++){
            this->matriz.setPos(xfin, y, 1);
        }
    }
}

Malla::Malla(const Malla& other){
    this->matriz = other.matriz;
    this->entrada = other.entrada;
    this->salida = other.salida;
}



bool Malla::operator==(const Malla& other){
    if(this != &other){
        return this->matriz == other.matriz
            && this->entrada == other.entrada
            && this->salida == other.salida;
    }
    return true;
}
bool Malla::operator!=(const Malla& other){
    return !(*this == other);
}


Malla& Malla::operator=(const Malla& other){
    if(this != &other){
        this->matriz = other.matriz;
        this->entrada = other.entrada;
        this->salida = other.salida;
    }
    return *this;
}

bool Malla::sonValidas() const{
        bool res;
        /*
        ______
        |C    |
        |     |
        |_____|
        */
        if(entrada.conexionEntrada() == NOROESTE){
            if(salida.conexionSalida() == NOROESTE){
                res = true;
            }else if(salida.conexionSalida() == NORESTE){
                res = salida.fila != entrada.fila-1 || salida.columna != entrada.columna;
            }else if(salida.conexionSalida() == SUDESTE){
                res = salida.fila != entrada.fila-1 || salida.columna != entrada.columna+1;
            }else if(salida.conexionSalida() == SUDOESTE){
                res = salida.fila != entrada.fila || salida.columna != entrada.columna+1;
            }
        /*
         ______
        |    C|
        |     |
        |_____|
        */
        }else if(entrada.conexionEntrada() == NORESTE){
            if(salida.conexionSalida() == NOROESTE){
                res = salida.fila != entrada.fila+1 || salida.columna != entrada.columna;
            }else if(salida.conexionSalida() == NORESTE){
                res = true;
            }else if(salida.conexionSalida() == SUDESTE){
                res = salida.fila != entrada.fila || salida.columna != entrada.columna+1;
            }else if(salida.conexionSalida() == SUDOESTE){
                res = salida.fila != entrada.fila+1 || salida.columna != entrada.columna+1;
            }

                /*
        ______
        |     |
        |     |
        |____C|

        */
        }else if(entrada.conexionEntrada() == SUDESTE){
            if(salida.conexionSalida() == NOROESTE){
                res = salida.fila != entrada.fila+1 || salida.columna != entrada.columna-1;
            }else if(salida.conexionSalida() == NORESTE){
                res = salida.fila != entrada.fila || salida.columna != entrada.columna-1;
            }else if(salida.conexionSalida() == SUDESTE){
                res = true;
            }else if(salida.conexionSalida() == SUDOESTE){
                res = salida.fila != entrada.fila+1 || salida.columna != entrada.columna;
            }
        /*
         ______
        |     |
        |     |
        |C____|
        */
        }else if(entrada.conexionEntrada() == SUDOESTE){
            if(salida.conexionSalida() == NOROESTE){
                res = salida.fila != entrada.fila || salida.columna != entrada.columna-1;
            }else if(salida.conexionSalida() == NORESTE){
                res = salida.fila != entrada.fila-1 || salida.columna != entrada.columna-1;
            }else if(salida.conexionSalida() == SUDESTE){
                res = salida.fila != entrada.fila-1 || salida.columna != entrada.columna;
            }else if(salida.conexionSalida() == SUDOESTE){
                res = true;
            }
        }
        return res;
}

bool Malla::setCelda(unsigned int fila, unsigned int columna){
    assert(existe(fila,columna));
    bool res = false;
    int tmp = this->matriz(fila, columna);
    if(tmp == 1)
        res = true;
    else if(tmp > 1)
        res = false;
    else {
        // no obstruye una entrada ni una salida
        // tiene una celda vecina
        bool vecina = esCelda(fila, columna -1)
                    || esCelda(fila, columna+1)
                    || esCelda(fila+1, columna)
                    || esCelda(fila-1, columna);
        if(vecina && conexionValida(fila, columna)){
                this->matriz.setPos(fila,columna,1);
        }

    }
    return res;
}

/** esta clase se fija si agregar una celda a la fila y columna
 * esta permitido en relacion a las entradas y salidas
 */
bool Malla::conexionValida(const unsigned  int fila,const unsigned  int columna) const{
    assert(existe(fila,columna));
//     __________
//     |  |  |  |
//     |__|__|__|
//     |  |OO|  |
//     |__|OO|__|
//     |  |  |  |
//     |__|__|__|
//
    bool res = true;
    //chequeo de entrada
    if(fila - 1 == entrada.fila){
        //     __________
        //     |  |  |  |
        //     |__|__|__|
        //     |  |22|  |
        //     |__|22|__|
        //     |11|11|11|
        //     |11|11|11|
        //
        if(columna - 1 == entrada.columna){
            //     __________
            //     |  |  |  |
            //     |__|__|__|
            //     |  |22|  |
            //     |__|22|__|
            //     |  |  |11|
            //     |__|__|11|
            //
            if(entrada.conexionEntrada() == SUDESTE){
                res =   !getCelda(entrada.fila, entrada.columna + 1).esCelda()
                        || !getCelda(entrada.fila + 1, entrada.columna).esCelda();
            }
        } else if (columna == entrada.columna) {
            //     __________
            //     |  |  |  |
            //     |__|__|__|
            //     |  |22|  |
            //     |__|22|__|
            //     |  |11|  |
            //     |__|11|__|
            //

            if(existe(entrada.fila,entrada.columna + 1) && entrada.conexionEntrada() == SUDESTE){
                res =   (matriz(entrada.fila, entrada.columna+1)==0)
                        || (matriz(entrada.fila + 1, entrada.columna+1)==0);
            }else if(existe(entrada.fila, entrada.columna-1) && entrada.conexionEntrada() == SUDOESTE){
                res =   (matriz(entrada.fila, entrada.columna-1)==0)
                || (matriz(entrada.fila+1, entrada.columna-1)==0);
            }

        } else if( columna + 1 == entrada.columna){
            //     __________
            //     |  |  |  |
            //     |__|__|__|
            //     |  |22|  |
            //     |__|22|__|
            //     |11|  |  |
            //     |11|__|__|
            //
            if(entrada.conexionEntrada() == SUDOESTE){
                    res =   (matriz(entrada.fila, entrada.columna - 1) == 0 )
                    || (matriz(entrada.fila + 1, entrada.columna) == 0);
                }
            }
    } else if (fila == entrada.fila){
        //     __________
        //     |  |  |  |
        //     |__|__|__|
        //     |11|22|11|
        //     |11|22|11|
        //     |  |  |  |
        //     |__|__|__|
        //

        if(columna - 1 == entrada.columna){
            //     __________
            //     |  |  |  |
            //     |__|__|__|
            //     |  |22|11|
            //     |__|22|11|
            //     |  |  |  |
            //     |__|__|__|
            //

            if(existe(entrada.fila + 1,entrada.columna) && entrada.conexionEntrada() == SUDESTE){
                res =   (matriz(entrada.fila + 1, entrada.columna + 1) == 0 )
                || (matriz(entrada.fila + 1, entrada.columna) == 0);
            } else if(existe(entrada.fila -1,entrada.columna) && entrada.conexionEntrada() == NORESTE){
                res =   (matriz(entrada.fila - 1, entrada.columna + 1) == 0 )
                || (matriz(entrada.fila - 1, entrada.columna) == 0);
            }
        } else if( columna + 1 == entrada.columna){
            //     __________
            //     |  |  |  |
            //     |__|__|__|
            //     |11|22|  |
            //     |11|22|__|
            //     |  |  |  |
            //     |__|__|__|
            //
            if(existe(entrada.fila+1,entrada.columna) && entrada.conexionEntrada() == SUDOESTE){
                res =   (matriz(entrada.fila + 1, entrada.columna - 1) == 0 )
                || (matriz(entrada.fila + 1, entrada.columna) == 0);
            } else if(existe(entrada.fila-1,entrada.columna) && entrada.conexionEntrada() == NOROESTE){
                res =   (matriz(entrada.fila - 1, entrada.columna - 1) == 0 )
                || (matriz(entrada.fila - 1, entrada.columna) == 0);
            }
        }

    } else if ( fila + 1 == entrada.fila){
        //     __________
        //     |11|11|11|
        //     |11|11|11|
        //     |  |22|  |
        //     |__|22|__|
        //     |  |  |  |
        //     |__|__|__
        //

        if(columna - 1 == entrada.columna){
            //     __________
            //     |  |  |11|
            //     |__|__|11|
            //     |  |22|  |
            //     |__|22|__|
            //     |  |  |  |
            //     |__|__|__|
            //
            if(entrada.conexionEntrada() == NORESTE){
                res =   (matriz(entrada.fila, entrada.columna + 1) == 0 )
                || (matriz(entrada.fila - 1, entrada.columna) == 0);
            }

        } else if (columna == entrada.columna) {
            //     __________
            //     |  |11|  |
            //     |__|11|__|
            //     |  |22|  |
            //     |__|22|__|
            //     |  |  |  |
            //     |__|__|__|
            //

            if(existe(entrada.fila,entrada.columna+1) && entrada.conexionEntrada() == NORESTE) {
                res =   (matriz(entrada.fila, entrada.columna+1)==0)
                || (matriz(entrada.fila - 1, entrada.columna+1)==0);
            }else if(existe(entrada.fila,entrada.columna-1) && entrada.conexionEntrada() == NOROESTE){
                res =   (matriz(entrada.fila, entrada.columna-1)==0)
                || (matriz(entrada.fila-1, entrada.columna-1)==0);
            }

        } else if( columna + 1 == entrada.columna){
            //     __________
            //     |11|  |  |
            //     |11|__|__|
            //     |  |22|  |
            //     |__|22|__|
            //     |  |  |  |
            //     |__|__|__|
            //
            if(entrada.conexionEntrada() == NOROESTE){
                res =   (matriz(entrada.fila, entrada.columna - 1) == 0 )
                || (matriz(entrada.fila - 1, entrada.columna) == 0);
            }
        }
    }
    bool resTemp = res;

    //chequeo de salida
    if(fila - 1 == salida.fila){
        //     __________
        //     |  |  |  |
        //     |__|__|__|
        //     |  |33|  |
        //     |__|33|__|
        //     |11|11|11|
        //     |11|11|11|
        //
        if(columna - 1 == salida.columna){
            //     __________
            //     |  |  |  |
            //     |__|__|__|
            //     |  |33|  |
            //     |__|33|__|
            //     |  |  |11|
            //     |__|__|11|
            //
            if(salida.conexionSalida() == SUDESTE){
                res =   (matriz(salida.fila, salida.columna + 1) == 0 )
                || (matriz(salida.fila + 1, salida.columna) == 0);
            }
        } else if (columna == salida.columna) {
            //     __________
            //     |  |  |  |
            //     |__|__|__|
            //     |  |33|  |
            //     |__|33|__|
            //     |  |11|  |
            //     |__|11|__|
            //

            if(existe(salida.fila, salida.columna + 1) && salida.conexionSalida() == SUDESTE){
                res =   (matriz(salida.fila, salida.columna+1)==0)
                || (matriz(salida.fila + 1, salida.columna+1)==0);
            }else if(existe(salida.fila, salida.columna - 1) && salida.conexionSalida() == SUDOESTE){
                res =   (matriz(salida.fila, salida.columna-1)==0)
                || (matriz(salida.fila+1, salida.columna-1)==0);
            }

        } else if( columna + 1 == salida.columna){
            //     __________
            //     |  |  |  |
            //     |__|__|__|
            //     |  |33|  |
            //     |__|33|__|
            //     |11|  |  |
            //     |11|__|__|
            //
            if(salida.conexionSalida() == SUDOESTE){
                res =   (matriz(salida.fila, salida.columna - 1) == 0 )
                || (matriz(salida.fila + 1, salida.columna) == 0);
            }
        }
    } else if (fila == salida.fila){
        //     __________
        //     |  |  |  |
        //     |__|__|__|
        //     |11|33|11|
        //     |11|33|11|
        //     |  |  |  |
        //     |__|__|__|
        //
        if(columna - 1 == salida.columna){
            //     __________
            //     |  |  |  |
            //     |__|__|__|
            //     |  |33|11|
            //     |__|33|11|
            //     |  |  |  |
            //     |__|__|__|
            //
            if(existe(salida.fila+1,salida.columna) && salida.conexionSalida() == SUDESTE){
                res =   (matriz(salida.fila + 1, salida.columna + 1) == 0 )
                || (matriz(salida.fila + 1, salida.columna) == 0);
            } else if(existe(salida.fila-1,salida.columna) && salida.conexionSalida() == NORESTE){
                res =   (matriz(salida.fila - 1, salida.columna + 1) == 0 )
                || (matriz(salida.fila - 1, salida.columna) == 0);
            }
        } else if( columna + 1 == salida.columna){
            //     __________
            //     |  |  |  |
            //     |__|__|__|
            //     |11|33|  |
            //     |11|33|__|
            //     |  |  |  |
            //     |__|__|__|
            //
            if(existe(salida.fila+1,salida.columna) && salida.conexionSalida() == SUDOESTE){
                res =   (matriz(salida.fila + 1, salida.columna - 1) == 0 )
                || (matriz(salida.fila + 1, salida.columna) == 0);
            } else if(existe(salida.fila-1,salida.columna) && salida.conexionSalida() == NOROESTE){
                res =   (matriz(salida.fila - 1, salida.columna - 1) == 0 )
                || (matriz(salida.fila - 1, salida.columna) == 0);
            }
        }
    } else if ( fila + 1 == salida.fila){
        //     __________
        //     |11|11|11|
        //     |11|11|11|
        //     |  |33|  |
        //     |__|33|__|
        //     |  |  |  |
        //     |__|__|__
        //
        if(columna - 1 == salida.columna){
            //     __________
            //     |  |  |11|
            //     |__|__|11|
            //     |  |33|  |
            //     |__|33|__|
            //     |  |  |  |
            //     |__|__|__|
            //
            if(salida.conexionSalida() == NORESTE){
                res =   (matriz(salida.fila, salida.columna + 1) == 0 )
                || (matriz(salida.fila - 1, salida.columna) == 0);
            }

        } else if (columna == salida.columna) {
            //     __________
            //     |  |11|  |
            //     |__|11|__|
            //     |  |33|  |
            //     |__|33|__|
            //     |  |  |  |
            //     |__|__|__|
            //

            if(existe(salida.fila, salida.columna + 1) && salida.conexionSalida() == NORESTE) {
                res =   (matriz(salida.fila, salida.columna+1)==0)
                || (matriz(salida.fila - 1, salida.columna+1)==0);
            }else if(existe(salida.fila, salida.columna - 1) && salida.conexionSalida() == NOROESTE){
                res =   (matriz(salida.fila, salida.columna-1)==0)
                || (matriz(salida.fila-1, salida.columna-1)==0);
            }

        }
        else if( columna + 1 == salida.columna){
            //     __________
            //     |11|  |  |
            //     |11|__|__|
            //     |  |33|  |
            //     |__|33|__|
            //     |  |  |  |
            //     |__|__|__|
            //
            if(salida.conexionSalida() == NOROESTE){
                res =   (matriz(salida.fila, salida.columna - 1) == 0 )
                || (matriz(salida.fila - 1, salida.columna) == 0);
            }
        }
    }
    return resTemp && res;
}



bool Malla::resetCelda(unsigned int fila, unsigned int columna){
    assert(existe(fila,columna));
    bool res = false;
    int tmp = this->matriz(fila, columna);
    if(tmp == 0)
        res = true;
    else if(tmp > 1)
        res = false;
    else {
		//una vez quitado todas las celdas deben seguir conectadas
        this->matriz.setPos(fila, columna, 0);
        res = validar();
        if(!res)
            this->matriz.setPos(fila, columna, 1);
    }
    return res;
}

bool Malla::validar() const{
    Matriz *booleana = new Matriz(this->matriz.size());
    pintarConectados(booleana, entrada.fila, entrada.columna);
    bool res = true;
    for(unsigned int i = 0; i < this->matriz.size(); i++){
        for(unsigned int j = 0; j < this->matriz.size(); j++){
           if(getCelda(i,j).esCelda()){
                res = res && (*booleana)(i,j) == 1;
           }
        }
    }
    return res;
}

/** funcion recursiva que intenta conectar a todos y ver que esten todos conectados */
void Malla::pintarConectados(Matriz* booleana, unsigned int fila, unsigned int columna) const {
    assert(esCelda(fila, columna));
    if((*booleana)(fila,columna) != 1){
        booleana->setPos(fila,columna,1);
        if(esCelda(fila, columna+1)){
            pintarConectados(booleana, fila, columna +1);
        }
        if(esCelda(fila, columna-1)){
            pintarConectados(booleana, fila, columna -1);
        }
        if(esCelda(fila + 1,columna)){
            pintarConectados(booleana, fila+1, columna);
        }
        if(esCelda(fila-1,columna)){
            pintarConectados(booleana, fila-1, columna);
        }
    }
}

Celda Malla::getCelda(unsigned int fila, unsigned int columna) const{
    assert(existe(fila,columna));
    Celda res;
    if(fila == this->entrada.fila && columna == this->entrada.columna){
        res = this->entrada;
    } else if(fila == this->salida.fila && columna == this->salida.columna){
        res = this->salida;
    } else if(this->matriz(fila, columna) == 0){
        res = Celda(fila, columna);
    } else {
        res = Celda(0,0,fila,columna);
    }
    return res;
}
float Malla::getResistencia() const {
    //arrId va a tener con un numero la intecidad Ik correspondiente y en -1 las que no tieen intencidad
    int arrId[matriz.size()*matriz.size()];
    int corriente=0;
    for(unsigned int i=0;i<matriz.size();i++) {
        for(unsigned int j=0;j<matriz.size();j++) {
            if(matriz(i,j)>0) {
                arrId[matriz.getId(i,j)]=corriente;
                corriente++;
            } else {
                arrId[matriz.getId(i,j)] = -1;
            }
        }
    }
    //hasta aca tenemos en arrId todas las intencidades implicadas, menos la externa
    //(aquellas que no tieenn -1 como valor) y estan numeradas!
    //ahora creamos arrRel que va de 0 a contador-1 y tiene en cada pos, el id de la celda que tiene ese numer
    unsigned int arrRel[corriente];
    for(unsigned int i=0; i < matriz.size()*matriz.size(); i++) {
        if(arrId[i] > -1){
            arrRel[arrId[i]]=i;
        }
    }

    //hasta aca tenemos en arrRel[i] el id the la intencidad_i
    //ahora vamos a crear una matriz de dimencion contador+1(matrizRes)
    //que entre [0..contador) va a estar las ecuaciones de la I_k y en contador va a estar la ecuacion importante
    Matriz matrizRes(corriente+1);
    //empezamos a resolver (recordemos que la matriz se inicializa en 0 c/pos)
    //CREO QUE CONVIENE HACER UN #define MATSIZE this->matriz.size() PARA QUE QUEDE MAS LINDO
    for(int i=0;i<corriente;i++) {
        matrizRes.setPos(i,i,4);
        if(arrRel[i] >= this->matriz.size()) {//puedo calcular la celda de arriba
            if(this->matriz(arrRel[i]-this->matriz.size())>0) { matrizRes.setPos(i,arrId[arrRel[i]-this->matriz.size()],-1); }
        }
        if(arrRel[i]%this->matriz.size()>0) { //puedo calcular la celda izquierda
            if(this->matriz(arrRel[i]-1)) { matrizRes.setPos(i,arrId[arrRel[i]-1],-1); }
        }
        if(arrRel[i]%this->matriz.size()<(this->matriz.size()-1)) { //puedo calcular la celda derecha
            if(this->matriz(arrRel[i]+1)) { matrizRes.setPos(i,arrId[arrRel[i]+1],-1); }
        }
        if(arrRel[i]<(this->matriz.size()*(this->matriz.size()-1))) { //puedo calcular la celda abajo
            if(this->matriz(arrRel[i]+this->matriz.size())) { matrizRes.setPos(i,arrId[arrRel[i]+this->matriz.size()],-1); }
        }
    }


    //arreglo donde se guarda la ultima fila que es igual a la columna.
    double *ultima = new double[corriente];
    for(int x = 0; x < corriente; x++){
        ultima[x] = 0;
    }
    //se recorre el borde de la malla contando cuantas veces se coinciden cada celda.
    //cout << "-----------------LA MALLA A RECORRER EL BORDE ES:" << endl;
    //cout << this->matriz << endl;
    recorrerLaberinto(ultima, arrId, corriente);


    int total = 0;
    for(int x = 0; x < corriente; x++){
        total += ultima[x];
        matrizRes.setPos(x, corriente, ultima[x]);
        matrizRes.setPos(corriente, x, ultima[x]);
    }
    matrizRes.setPos(corriente, corriente, -total);
    //chequear que sea simetrica y que las corrientes sumen 0 en cada fila.
    //COMPLETAR
    //arreglo con los voltajes
    double *voltajes = new double[corriente+1];
    double *resistencias = new double[corriente + 1];

    for(int i = 0; i < corriente + 1; i++){
        voltajes[i] = 0;
        resistencias[i] = 0;
    }
    voltajes[corriente] = 1;
    //bien, hasta aca tenemos la matriz con todas las cosas
    //cout << matrizRes << endl;
    assert(matrizRes.resolver(voltajes, resistencias));
    //assert(resistencias[corriente] > 0);
    return 1/resistencias[corriente];
}

int Malla::size() const {
	return this->matriz.size();
}

void Malla::recorrerLaberinto(double* ultima, int * arrId, int tamanio) const{
        Dupla<int,int> dir;
        Dupla<unsigned int, unsigned int> pos(entrada.fila, entrada.columna);
        unsigned int esquina = direccionInicial(dir, pos);



        //mientras no halla llegado a la conexion del otro lado
        while(pos.fila!=salida.fila || pos.columna!=salida.columna || esquina != salida.conexionSalida()){
            //cout << "dir:"<<dir <<" pos:"<< pos << "  nodo:"<< esquina << endl;
            assert(esCelda(pos.fila, pos.columna));
            int id = this->matriz.getId(pos.fila, pos.columna);
            int corriente = arrId[id];
            ultima[corriente] -= 1;
            esquina = proximaCelda(dir, pos, esquina);
        }

}


void abajo(Dupla<int,int>& dir){
    dir.fila = 1;
    dir.columna = 0;
}

void arriba(Dupla<int,int>& dir){
    dir.fila = -1;
    dir.columna = 0;
}

void izquierda(Dupla<int,int>& dir){
    dir.fila = 0;
    dir.columna = -1;
}

void derecha(Dupla<int,int>& dir){
    dir.fila = 0;
    dir.columna = 1;
}


bool esAbajo(const Dupla<int,int>& dir){
    Dupla<int,int> temp;
    abajo(temp);
    return temp == dir;
}

bool esArriba(const Dupla<int,int> &dir){
    Dupla<int,int> temp;
    arriba(temp);
    return temp == dir;
}

bool esDerecha(const Dupla<int,int> &dir){
    Dupla<int,int> temp;
    derecha(temp);
    return temp == dir;
}

bool esIzquierda(const Dupla<int,int> &dir){
    Dupla<int,int> temp;
    izquierda(temp);
    return temp == dir;
}

void girarHorario(Dupla<int,int>& dir){
    int temp = dir.fila;
    dir.fila = dir.columna;
    dir.columna = -temp;
}

void girarAntiHorario(Dupla<int, int>& dir){
    int temp = dir.fila;
    dir.fila = -dir.columna;
    dir.columna = temp;
}

bool Malla::esCelda(unsigned int fila, unsigned int columna) const {
        return existe(fila, columna) && getCelda(fila, columna).esCelda();
}

bool Malla::esCelda(Dupla<unsigned int, unsigned int> coord) const{
    return existe(coord.fila, coord.columna) && getCelda(coord.fila, coord.columna).esCelda();
}

/** en sentido horario*/
unsigned int horarioProxEsquina(int esquina) {
    int res = (esquina+1)%4;
    if(res == 0){
        res = 4;
    }
    return res;
}

unsigned int antiHorarioProxEsquina(int esquina){
    int res = (esquina-1)%4;
    if(res == 0){
        res = 4;
    }
    return res;
}

bool esHorario(const Dupla<int,int>& dir, int esquina){
    bool res;
    if(esDerecha(dir))
        res = (esquina == NOROESTE);
    else if(esAbajo(dir))
        res = (esquina == NORESTE);
    else if(esIzquierda(dir))
        res = (esquina == SUDESTE);
    else if(esArriba(dir))
        res = (esquina == SUDOESTE);
    else
        assert(false);
    return res;
}

int Malla::proximaCelda(Dupla<int,int>& dir, Dupla<unsigned int, unsigned int>& pos, int esquina) const{
    /* referencia:

    ________________
    |       |       |
    | POS   |  CJ   |
    |b_____d|_______|
    | -->A  |c      |
    | VACIA |  CK   |
    |_______|_______|

    POS = celda actual
    CJ = celda J
    CK = celda k
    b = esquina actual
    d = esquina misma celda
    c = esquina otra celda
    --->A = direccion actual (dir)
    (POS + dirVacia == VACIA) dirVacia apunta hacia donde esta la celda vacia.
    dado A si apunto (en este ejmplo) hacia abajo obtengo dirVacia
    y dirNueva es la misma direccion de dirVacia pero en sentido opuesto.

    */
    
    Dupla<unsigned int, unsigned int> prepos(pos);
    Dupla<int,int> predir(dir);
    int presquina = esquina;
    bool horario = esHorario(dir, esquina);
    Dupla<int,int> dirVacia(dir);
    Dupla<int,int> dirNueva(dir);
    int esquinaMismaCelda, esquinaOtraCelda;
    if(horario){
        girarAntiHorario(dirVacia);
        girarHorario(dirNueva);
        esquinaMismaCelda = horarioProxEsquina(esquina);
        esquinaOtraCelda = antiHorarioProxEsquina(esquina);
    } else {
        girarHorario(dirVacia);
        girarAntiHorario(dirNueva);
        esquinaMismaCelda = antiHorarioProxEsquina(esquina);
        esquinaOtraCelda = horarioProxEsquina(esquina);

    }

    //la celda q esta al otro lado del vertice es vacia.
    assert(!esCelda(pos.fila + dirVacia.fila, pos.columna + dirVacia.columna));
    //las proximas 2 celdas son vacias, hay q seguir girando.
    if(     !esCelda(pos.fila + dir.fila, pos.columna + dir.columna)
            && !esCelda(pos.fila + dir.fila + dirVacia.fila, pos.columna + dir.columna + dirVacia.columna)){
        dir = dirNueva;
        esquina = esquinaMismaCelda;
        //la celda a la que estoy apuntando existe, pero la del costado a esa no.
    } else if (!esCelda(pos.fila + dir.fila + dirVacia.fila, pos.columna + dir.columna + dirVacia.columna)){
        pos.fila += dir.fila;
        pos.columna += dir.columna;
        // las 2 celdas que estan adelante estan ocupadas (giro hacia el otro lado)
    } else {
        pos.fila += (dir.fila + dirVacia.fila);
        pos.columna += (dir.columna + dirVacia.columna);
        dir = dirVacia;
        esquina = esquinaOtraCelda;
    }

    //si es la misma celda
    if(pos == prepos){
        assert(esquina != presquina && predir != dir);
    } else if(dir == predir) {
        assert(esquina == presquina);
    }
    return esquina;
}

Dupla<int,int> orientacion(int esquina){
    Dupla<int,int> res;
    if(esquina == NOROESTE){
        res.fila = -1;
        res.columna = -1;
    } else if(esquina == NORESTE){
        res.fila = -1;
        res.columna = 1;
    } else if(esquina == SUDESTE){
        res.fila = 1;
        res.columna = 1;
    } else if(esquina == SUDOESTE){
        res.fila = 1;
        res.columna = -1;
    } else {
        assert(false);
    }
    return res;
}


int Malla::direccionInicial(Dupla<int,int>& dir, Dupla<unsigned int, unsigned int>& pos) const{
    int esquina = entrada.conexionEntrada();
    Dupla<int,int> direccionEsquina = orientacion(esquina);
    Dupla<int,int> proyeccionFila(direccionEsquina);
    Dupla<int,int> proyeccionColumna(direccionEsquina);
    proyeccionColumna.fila = 0;
    proyeccionFila.columna = 0;
    
    if(!esCelda(pos.fila+proyeccionFila.fila, pos.columna + proyeccionFila.columna)){
        proyeccionColumna.columna = - proyeccionColumna.columna;
        dir = proyeccionColumna;
    } else if (!esCelda(pos.fila+proyeccionColumna.fila, pos.columna + proyeccionColumna.columna)){
        proyeccionFila.fila = - proyeccionFila.fila;
        dir = proyeccionFila;
    } else if(!esCelda(pos.fila+direccionEsquina.fila, pos.columna + direccionEsquina.columna)){
        pos.fila = pos.fila + proyeccionColumna.fila;
        pos.columna = pos.columna + proyeccionColumna.columna;
        dir = proyeccionColumna;
        int esquina = horarioProxEsquina(esquina);
    } else {
        assert(false);
    }
    return esquina;
    
}


void Malla::show(double val=0) const {
    string txt="<html>";
    txt+="<head><style type='text/css'>";
    txt+="table tr td { width: 50px;height: 47px;text-align: center; }";
    txt+="td.type_1 {background-image: url('malla/imgs/celda_1.jpg'); background-repeat: no-repeat; }";
    txt+="td.type_2 {background-image: url('malla/imgs/celda_2.jpg'); background-repeat: no-repeat; }";
    txt+="td.type_3 {background-image: url('malla/imgs/celda_3.jpg'); background-repeat: no-repeat; }";
    txt+="</style></head><body>";
        txt+="<table cellspacing='0' cellpadding='0'>";
            for(unsigned int i=0;i<matriz.size();i++) {
                txt+="<tr>";
                for(unsigned int j=0;j<matriz.size();j++) {
                    ostringstream aux;
                    aux << matriz(i,j);
                    txt+= "<td class='type_";
                    txt+= aux.str();
                    txt+="'>";
                    txt+= aux.str();
                    txt+="</td>";
                }
                txt+="</tr>";
            }
        txt+="</table>";
    stringstream s;
    s << "Entrada: " << this->entrada << "<br/>";
    s << "Salida: " << this->salida << "<br/>";
    txt += s.str();
    txt+="</body></html>";
    stringstream ss;
    ss << "malla" << this << val << ".htm";
    string nombre = ss.str();
    ofstream html(nombre.c_str());
    html<<txt;
    html.close();
}

bool Malla::existe(const unsigned int fila, const unsigned int columna) const {
    bool res;
    res = fila >= 0 && fila < this->matriz.size();
    res = res && columna >= 0 && columna < this->matriz.size();
    return res;
}

ostream& operator<<(ostream& out, const Malla& m) {
    m.mostrar(out);
    return out;
}

void Malla::mostrar(ostream& out) const{
    out << this->matriz << endl;
    out << this->entrada << endl;
    out << this->salida << endl;
}

#endif

